﻿/**
  *@brief 这是一个非常复杂的，C++11可变参模板应用实例
  *       目前可以不用深入学习，用基本的就可以了
  *       模板是很复杂的，使用时，还是根据需求来设计，不要想
  *       一些不存在的场景
  *
*/
#ifndef TYPETUPLE_H
#define TYPETUPLE_H
//////////////////////////////////////////////////////////
template<typename... TList> struct tuple;

template<> struct tuple<> {};

typedef tuple<> nulltuple;


//////////////////////////////////////////////////////////
template<typename T, typename... TList>
struct tuple<T, TList...> : public tuple<TList...>
{
    typedef T value_type;
    typedef tuple<TList...> base_type;

    tuple(T v, TList... tails):_value(v),base_type(tails...) {}

    const T& head() const { return this->_value; }
    T& head() { return this->_value; }

protected:
    T _value;
};

template<typename T>
struct tuple<T> : public nulltuple
{
    typedef T value_type;
    typedef nulltuple base_type;

    tuple(T v):_value(v) {}

    const T& head() const { return this->_value; }
    T& head() { return this->_value; }

protected:
    T _value;
};


//////////////////////////////////////////////////////////
template<unsigned int N, typename... TList> struct tuple_at;

//为了得到2的类型，0和1的类型也要递归地进行获取,可以从N==0开始理解
//这个模板就是为了按顺序得到各个类型，并在自己内部进行声明
//TList...与N应当是同级别的展开
template<unsigned int N, typename T, typename... TList>
struct tuple_at< N, tuple<T, TList...> >
{
    typedef typename tuple_at< N-1, tuple<TList...> >::value_type value_type;
    typedef typename tuple_at< N-1, tuple<TList...> >::tuple_type tuple_type;
};

template<typename T, typename... TList>
struct tuple_at< 0, tuple<T, TList...> >
{
    typedef T value_type;
    typedef tuple<T, TList...> tuple_type;
};

template<>
struct tuple_at<0, nulltuple>
{
    typedef nulltuple value_type;
    typedef nulltuple tuple_type;
};

//////////////////////////////////////////////////////////
template<unsigned int N, typename... TList> struct tuple_helper;

template<unsigned int N, typename T, typename... TList>
struct tuple_helper<N, tuple<T, TList...>>
{
    typedef tuple<T, TList...> tuple_type;
    typedef typename tuple_at<N, tuple_type>::tuple_type base_tuple_type;
    typedef typename tuple_at<N, tuple_type>::value_type return_type;

    constexpr static const return_type& get(const tuple_type& tuple_)
    {
        //return static_cast<const base_tuple_type&>(tuple_).head();
        return static_cast<const base_tuple_type&>(tuple_).head();
    }

    static void get(const nulltuple& tuple_) {}
};

//////////////////////////////////////////////////////////
template<unsigned int N, typename... TList>
constexpr const typename tuple_at<N, tuple<TList...> >::value_type&
tuple_get(const tuple<TList...>& tuple_)
{
    return tuple_helper< N, tuple<TList...> >::get(tuple_);
}

//如下是for main.cpp的，暂存
//tuple<int,float,char> mytuple = {11,5.98,'c'};
//bool b;
//b = std::is_same<tuple_at<2,tuple<int,float,char>>::value_type,char>::value;
//std::cout<<"is same : "<<b<<std::endl;

//b = std::is_same<tuple_at<2,tuple<int,float,char>>::tuple_type,tuple<char>>::value;
//std::cout<<"is same : "<<b<<std::endl;

//std::cout<<tuple_get<0>(mytuple)<<" "<<tuple_get<1>(mytuple)<<" "<<tuple_get<2>(mytuple)
//        <<std::endl;

#endif // TYPETUPLE_H
